/*
 *  Smtp.h
 *  MinimalSmtp
 *
 *  Created by Andrey on 10/12/2008.
 *  Copyright 2008 Karma Software. All rights reserved.
 *
 */

/** \file Smtp.h
	\brief Файл, содержащий описания структур данных и функций, составляющих 
	интерфейс к реализации протокола SMTP 
 */

#ifndef SMTP
#define SMTP

#include <KBaseTypes.h>
#include <KAnsiCWrappers.h>
#include "SmtpLimits.h"
#include "SmtpReplies.h"
#include "../NetTalk/DataBuffer.h"
#include "SmtpFsm.h"
#include "SmtpPseudocode.h"

/** \enum SmtpCommandType
	\brief Перечисление, описывающее типы команд протокола SMTP
 */
enum SmtpCommandType {
	Initiation,
	MailTransactionStart,
	RecipientInfo,
	MessageContents,
	NoOperation,
	Reset,
	Quit
};

BEGIN_STRUCT_DECLARATION(MailboxAddress)
	AsciiChar localPart[MAX_USERNAME_LENGTH];
	//!< Имя пользователя
	AsciiChar domain[MAX_DOMAIN_LENGTH];
	//!< Имя домена
END_STRUCT_DECLARATION(MailboxAddress)

/** \struct SmtpCommandHeader
	\brief Структура данных, представляющая собой заголовок команды протокола
	SMTP и содержащая тип этой команды. 
 
	С помощью этой структуры имитируется некое подобие наследования, так как в 
	«производных» структурах типа SmtpCommandWithDomain или SmtpCommandWithAddress 
	это поле всегда находится первым, поэтому указатели на эти структуры можно
	приводить к указателю на «базовую» структуру SmtpCommandHeader (с помощью
	макроса COMMAND_TO_HEADER) и по указателю на заголовок получать указатель
	на всю структуру (с помощью макроса HEADER_TO_COMMAND).
 */
BEGIN_STRUCT_DECLARATION(SmtpCommandHeader)
	enum SmtpCommandType type;
	//!< Тип SMTP-команды
END_STRUCT_DECLARATION(SmtpCommandHeader)

/** \struct SmtpCommandWithDomain
	\brief Структура, представляющая собой команду протокола SMTP, содержащую
	в себе имя домена
 */
BEGIN_STRUCT_DECLARATION(SmtpCommandWithDomain)
	SmtpCommandHeader header;
	//!< Заголовок SMTP-команды
	AsciiChar domain[MAX_DOMAIN_LENGTH];
	//!< Имя домена
END_STRUCT_DECLARATION(SmtpCommandWithDomain)

/** \struct SmtpCommandWithAddress
	\brief Структура, представляющая собой команду протокола SMTP, содержащую
	в себе почтовый адрес
 */
BEGIN_STRUCT_DECLARATION(SmtpCommandWithAddress)
	SmtpCommandHeader header;
	//!< Заголовок SMTP-команды
	MailboxAddress address;
	//!< Почтовый адрес
END_STRUCT_DECLARATION(SmtpCommandWithAddress)

BEGIN_STRUCT_DECLARATION(SmtpCommandWithData)
	SmtpCommandHeader header;
	AsciiChar data[MAX_TEXT_LINE_LENGTH];
END_STRUCT_DECLARATION(SmtpCommandWithData)

/** \struct SmtpControlCommand
	\brief Структура, представляющая собой команду управляющую команду протокола 
	SMTP
 */
BEGIN_STRUCT_DECLARATION(SmtpControlCommand)
	SmtpCommandHeader header;
	//!< Заголовок SMTP-команды
END_STRUCT_DECLARATION(SmtpControlCommand)

/** \def HEADER_TO_COMMAND
	Макрос, позволяющий по указателю на заголовок SMTP-команды получить указатель
	на всю команду
 */
#define HEADER_TO_COMMAND(Header, CommandType) ((CommandType##Ptr)(Header))

/**	\struct SmtpEnvelope
	\brief Структура, хранящая заголовки и текст письма
 */
BEGIN_STRUCT_DECLARATION(SmtpEnvelope)
	MailboxAddress sender;
	//!< Адрес отправителя
	MailboxAddress recipients[MAX_RECIPIENT_COUNT];
	//!< Адреса получателей
	int recipientCount;
	//!< Количество получателей
	DataBuffer messageContents;
	//!< Текст самого письма
END_STRUCT_DECLARATION(SmtpEnvelope)

/** \fn Boolean ParseDataFromClient(DataBuffer clientData, SmtpCommandHeaderPtr commandHeader);
	\brief Функция, осуществляющая разбор строки, полученной от клиента, и
	возвращающая (в случае удачи) заполненную структуру данных, содержащую
	информацию о полученной команде и её параметрах
	\param DataBuffer clientData -- буфер, содержащий строку, которую необходимо
	разобрать
	\param SmtpCommandHeaderPtr commandHeader -- указатель на заголовок команды,
	который будет проинициализирован адресом структуры с типом и параметрами 
	команды
	\return YES в случае, если переданная строка являлась допустимой SMTP-командой,
	NO -- в противном случае
	\warning Память, выделенную под структуру команды, должна освобождать 
	вызывающая сторона.
 */
Boolean ParseDataFromClient(DataBuffer clientData, SmtpCommandHeaderPtr commandHeader);

void WriteSmtpReplyToBuffer(DataBuffer replyBuffer, int replyCode);

enum SmtpEvent SmtpCommandTypeToFsmEvent(enum SmtpCommandType type);

void PreparseDataFromClient(DataBuffer clientData);

SmtpCommandHeaderPtr ParseDataFromClientManually(DataBuffer clientData);

void ShowEnvelope(SmtpEnvelopePtr envelope);

#endif